package com.atguigu.filechannel.nio;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

/**
 * 使用SocketChannel实现TCP协议的文件传输
 * NIO中的SocketChannel和OIO中的Socket对应
 * NIO中的ServerSocketChannel和OIO中的ServerSocket对应
 */
public class Client{
    public static void main(String[] args) {
        //先启动服务端，再启动客户端
        Client client = new Client();

        //发送文件
        String filepath = System.getProperty("user.dir")+"\\zaedu-charge-system\\charge-system\\target\\";
        client.upload(filepath,"charge-system.jar");

    }

    private final Charset charset = Charset.forName("UTF-8");//java默认编码为Unicode，有的操作系统不支持，统一编码格式为UTF-8
    private final String serverAddress = "localhost";
    private final int serverPort = 9111;

    /**
     * 传递到服务端的应该有文件路径和文件名
     * @param filepath
     * @param filename
     */
    public void upload(String filepath,String filename)  {
        try{
            File sendfile = new File(filepath+filename);
            FileChannel fileChannel = new FileInputStream(sendfile).getChannel();//获取该文件的输入流的通道

            SocketChannel socketChannel = SocketChannel.open();//打开Socket通道
            socketChannel.connect(new InetSocketAddress(serverAddress,serverPort));//绑定服务器的链接地址和端口号
            socketChannel.configureBlocking(false);//设置为非阻塞式

            //由于是非阻塞式连接，所以socketChannel.connect()方法不论是否真正的连接成功，都会立即返回，
            while(!socketChannel.finishConnect()){
                //socket没有真正连接前，不断的自旋、等待，或者做一些其他的事情
                System.out.println("等待连接中，做其他事....");
            }
            System.out.println("成功连接到服务器...");
            //将存储在服务器的文件名编码为UTF-8格式的二进制字节序列
            ByteBuffer fileNamebuffer = charset.encode(filename);
            socketChannel.write(fileNamebuffer);//将文件名传过去

            System.out.println("开始传输文件");
            ByteBuffer filebuffer = ByteBuffer.allocate(1024);//开启缓冲内存区域，用于存储文件内容
            int len = 0;
            while((len = fileChannel.read(filebuffer)) != -1){//将文件数据从fileChannel读取并存储到filebuffer缓冲区中
                filebuffer.flip();//将内存缓冲区翻转为读模式
                socketChannel.write(filebuffer);//读取本次缓冲区所有文件并写入通道
                filebuffer.clear();//清空缓冲区
            }

            //单向关闭，表示客户端数据写完了，如果需要服务端响应数据，就要用这种方式
//            socketChannel.shutdownOutput();

            //读完文件通道关闭
            fileChannel.close();
            socketChannel.close();
            System.out.println("传输完成...");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
